<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>用例图生成器</title>
  <!-- Tailwind CSS Play CDN for development -->
  <!-- 注意：在生产环境中，请使用 PostCSS 插件或 Tailwind CLI 安装 Tailwind CSS -->
  <!-- 参考：https://tailwindcss.com/docs/installation -->
  <script src="assets/css/tailwindcss.js"></script>
  <link href="assets/css/font-awesome-full.css" rel="stylesheet">
  
  <!-- GoJS Library with multiple fallbacks -->
  <script>
    // GoJS loading with fallbacks - using latest stable versions
    (function() {
      const gojsUrls = [
        'https://unpkg.com/gojs/release/go.js',
        'https://cdn.jsdelivr.net/npm/gojs/release/go.js',
        'https://unpkg.com/gojs@2.1/release/go.js',
        'https://cdn.jsdelivr.net/npm/gojs@2.1/release/go.js'
      ];
      
      let currentIndex = 0;
      
      function loadGoJS() {
        if (currentIndex >= gojsUrls.length) {
          console.error('All GoJS CDN sources failed to load');
          window.gojsLoadError = true;
          return;
        }
        
        const script = document.createElement('script');
        script.src = gojsUrls[currentIndex];
        script.onload = function() {
          console.log('GoJS loaded successfully from:', gojsUrls[currentIndex]);
          window.gojsLoaded = true;
        };
        script.onerror = function() {
          console.warn('Failed to load GoJS from:', gojsUrls[currentIndex]);
          currentIndex++;
          loadGoJS();
        };
        document.head.appendChild(script);
      }
      
      loadGoJS();
    })();
  </script>
  
  <link href="assets/css/inter-font.css" rel="stylesheet">
  
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#165DFF',
            secondary: '#722ED1',
            neutral: {
              50: '#F5F7FA',
              100: '#E5E6EB',
              200: '#C9CDD4',
              300: '#86909C',
              400: '#4E5969',
              500: '#1D2129',
            },
            dark: {
              50: '#2C2C34',
              100: '#25252B',
              200: '#1D1D21',
              300: '#151518',
              400: '#0C0C0E',
              500: '#000000',
            },
            success: '#00B42A',
            warning: '#FF7D00',
            danger: '#F53F3F',
            info: '#168CFF',
          },
          fontFamily: {
            inter: ['Inter', 'sans-serif'],
          },
          boxShadow: {
            'card': '0 4px 20px rgba(0, 0, 0, 0.08)',
            'card-hover': '0 8px 30px rgba(0, 0, 0, 0.12)',
            'button': '0 2px 8px rgba(22, 93, 255, 0.25)',
          },
        },
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    /* 主题系统 CSS 变量 */
    :root {
      /* 明亮主题 */
      --bg-primary: #F5F7FA;
      --bg-secondary: #FFFFFF;
      --bg-tertiary: #E5E6EB;
      --text-primary: #1D2129;
      --text-secondary: #4E5969;
      --text-tertiary: #86909C;
      --border-primary: #E5E6EB;
      --border-secondary: #C9CDD4;
      --shadow-primary: rgba(0, 0, 0, 0.08);
      --shadow-secondary: rgba(0, 0, 0, 0.12);
      --diagram-bg: #FFFFFF;
      --node-fill: #FFFFFF;
      --node-stroke: #000000;
      --link-stroke: #000000;
      --highlight-fill: #F0F0F0;
    }

    [data-theme="dark"] {
      /* 暗黑主题 */
      --bg-primary: #0C0C0E;
      --bg-secondary: #151518;
      --bg-tertiary: #1D1D21;
      --text-primary: #FFFFFF;
      --text-secondary: #C9CDD4;
      --text-tertiary: #86909C;
      --border-primary: #25252B;
      --border-secondary: #2C2C34;
      --shadow-primary: rgba(0, 0, 0, 0.3);
      --shadow-secondary: rgba(0, 0, 0, 0.5);
      --diagram-bg: #151518;
      --node-fill: #25252B;
      --node-stroke: #C9CDD4;
      --link-stroke: #C9CDD4;
      --highlight-fill: #2C2C34;
    }

    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .text-shadow {
        text-shadow: 0 2px 4px rgba(0,0,0,0.1);
      }
      .card-hover {
        @apply transition-all duration-300 hover:shadow-card-hover hover:-translate-y-1;
      }
      .btn-primary {
        @apply bg-primary text-white px-4 py-2 rounded-lg shadow-button hover:bg-primary/90 transition-all duration-300 flex items-center justify-center gap-2;
      }
      .btn-secondary {
        background-color: var(--bg-secondary);
        border: 1px solid var(--border-primary);
        color: var(--text-secondary);
        @apply px-4 py-2 rounded-lg shadow-sm transition-all duration-300 flex items-center justify-center gap-2;
      }
      .btn-secondary:hover {
        background-color: var(--bg-tertiary);
        color: var(--text-primary);
      }
      .btn-icon {
        @apply p-2 rounded-lg transition-all duration-200;
      }
      .btn-icon:hover {
        background-color: var(--bg-tertiary);
      }
      .input-field {
        background-color: var(--bg-secondary);
        border: 1px solid var(--border-primary);
        color: var(--text-primary);
        @apply w-full px-4 py-3 rounded-lg focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none transition-all duration-200;
      }
      .panel {
        background-color: var(--bg-secondary);
        border: 1px solid var(--border-primary);
        box-shadow: 0 4px 20px var(--shadow-primary);
        @apply rounded-xl overflow-hidden;
      }
      .full-height {
        height: calc(100vh - 4rem);
      }
      .animate-pulse-slow {
        animation: pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
      }
      .gradient-bg {
        background: linear-gradient(135deg, #165DFF 0%, #722ED1 100%);
      }
      .text-gradient {
        background-clip: text;
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-image: linear-gradient(135deg, #165DFF 0%, #722ED1 100%);
      }
      .theme-transition {
        transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease;
      }
    }
  </style>
</head>
<body class="font-inter text-neutral-500 overflow-hidden theme-transition" style="background-color: var(--bg-primary); color: var(--text-primary);">
  <!-- 顶部导航栏 -->
  <header class="px-6 py-3 flex justify-between items-center border-b theme-transition" style="background-color: var(--bg-secondary); border-color: var(--border-primary); box-shadow: 0 1px 3px var(--shadow-primary);">
    <div class="flex items-center">
      <div class="w-8 h-8 rounded-lg gradient-bg flex items-center justify-center text-white mr-3">
        <i class="fa fa-users"></i>
      </div>
      <h1 class="text-xl font-bold" style="color: var(--text-primary);">
        <span class="text-gradient">用例图</span>生成器
      </h1>
    </div>
    <div class="flex items-center gap-4">
      <button id="helpBtn" class="btn-icon">
        <i class="fa fa-question-circle hover:text-primary" style="color: var(--text-tertiary);"></i>
      </button>
      <button id="settingsBtn" class="btn-icon">
        <i class="fa fa-cog hover:text-primary" style="color: var(--text-tertiary);"></i>
      </button>
      <button id="themeToggle" class="btn-icon" title="切换主题">
        <i id="themeIcon" class="fa fa-moon-o hover:text-primary" style="color: var(--text-tertiary);"></i>
      </button>
    </div>
  </header>
  
  <!-- 个性化设置面板 -->
  <div id="customizePanel" class="border-b px-6 py-4 hidden theme-transition" style="background-color: var(--bg-secondary); border-color: var(--border-primary);">
    <div class="flex items-center justify-between mb-4">
      <h3 class="text-lg font-semibold flex items-center" style="color: var(--text-secondary);">
        <i class="fa fa-palette text-primary mr-2"></i>个性化设置
      </h3>
      <button id="closeCustomizeBtn" class="transition-colors duration-200" style="color: var(--text-tertiary);" onmouseover="this.style.color='var(--text-secondary)'" onmouseout="this.style.color='var(--text-tertiary)'">
        <i class="fa fa-times"></i>
      </button>
    </div>
    
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6">
      <!-- 主题设置 -->
      <div class="space-y-3">
        <h4 class="text-sm font-medium flex items-center" style="color: var(--text-tertiary);">
          <i class="fa fa-adjust text-primary mr-2"></i>主题设置
        </h4>
        <div class="space-y-2">
          <div>
            <label class="block text-xs mb-1" style="color: var(--text-tertiary);">主题模式</label>
            <div class="flex items-center gap-3">
              <label class="flex items-center cursor-pointer">
                <input type="radio" name="themeOption" value="light" id="themeLight" class="mr-2" checked>
                <span class="text-sm" style="color: var(--text-secondary);">明亮</span>
              </label>
              <label class="flex items-center cursor-pointer">
                <input type="radio" name="themeOption" value="dark" id="themeDark" class="mr-2">
                <span class="text-sm" style="color: var(--text-secondary);">暗黑</span>
              </label>
            </div>
          </div>
          <div>
            <label class="block text-xs mb-1" style="color: var(--text-tertiary);">自动切换</label>
            <label class="flex items-center cursor-pointer">
              <input type="checkbox" id="autoTheme" class="mr-2">
              <span class="text-sm" style="color: var(--text-secondary);">跟随系统</span>
            </label>
          </div>
        </div>
      </div>
      
      <!-- 字体设置 -->
      <div class="space-y-3">
        <h4 class="text-sm font-medium flex items-center" style="color: var(--text-tertiary);">
          <i class="fa fa-font text-primary mr-2"></i>字体设置
        </h4>
        <div class="space-y-2">
          <div>
            <label class="block text-xs mb-1" style="color: var(--text-tertiary);">字体大小</label>
            <select id="fontSizeSelect" class="w-full px-3 py-2 text-sm rounded-lg focus:border-primary focus:ring-1 focus:ring-primary/20 outline-none theme-transition" style="border: 1px solid var(--border-primary); background-color: var(--bg-secondary); color: var(--text-primary);">
              <option value="12">12px</option>
              <option value="14" selected>14px</option>
              <option value="16">16px</option>
              <option value="18">18px</option>
              <option value="20">20px</option>
              <option value="24">24px</option>
            </select>
          </div>
          <div>
            <label class="block text-xs mb-1" style="color: var(--text-tertiary);">字体颜色</label>
            <div class="flex items-center gap-2">
              <input type="color" id="fontColorPicker" value="#1D2129" class="w-8 h-8 rounded cursor-pointer" style="border: 1px solid var(--border-primary);">
              <input type="text" id="fontColorInput" value="#1D2129" class="flex-1 px-2 py-1 text-xs rounded focus:border-primary outline-none theme-transition" style="border: 1px solid var(--border-primary); background-color: var(--bg-secondary); color: var(--text-primary);">
            </div>
          </div>
        </div>
      </div>
      
      <!-- 角色样式 -->
      <div class="space-y-3">
        <h4 class="text-sm font-medium text-neutral-300 flex items-center">
          <i class="fa fa-user text-primary mr-2"></i>角色样式
        </h4>
        <div class="space-y-2">
          <div>
            <label class="block text-xs text-neutral-300 mb-1">背景颜色</label>
            <div class="flex items-center gap-2">
              <input type="color" id="entityBgColorPicker" value="#165DFF" class="w-8 h-8 rounded border border-neutral-100 cursor-pointer">
              <input type="text" id="entityBgColorInput" value="#165DFF" class="flex-1 px-2 py-1 text-xs border border-neutral-100 rounded focus:border-primary outline-none">
            </div>
          </div>
          <div>
            <label class="block text-xs text-neutral-300 mb-1">边框颜色</label>
            <div class="flex items-center gap-2">
              <input type="color" id="entityBorderColorPicker" value="#0E4BC6" class="w-8 h-8 rounded border border-neutral-100 cursor-pointer">
              <input type="text" id="entityBorderColorInput" value="#0E4BC6" class="flex-1 px-2 py-1 text-xs border border-neutral-100 rounded focus:border-primary outline-none">
            </div>
          </div>
        </div>
      </div>
      
      <!-- 功能样式 -->
      <div class="space-y-3">
        <h4 class="text-sm font-medium text-neutral-300 flex items-center">
          <i class="fa fa-circle text-secondary mr-2"></i>功能样式
        </h4>
        <div class="space-y-2">
          <div>
            <label class="block text-xs text-neutral-300 mb-1">背景颜色</label>
            <div class="flex items-center gap-2">
              <input type="color" id="attrBgColorPicker" value="#722ED1" class="w-8 h-8 rounded border border-neutral-100 cursor-pointer">
              <input type="text" id="attrBgColorInput" value="#722ED1" class="flex-1 px-2 py-1 text-xs border border-neutral-100 rounded focus:border-primary outline-none">
            </div>
          </div>
          <div>
            <label class="block text-xs text-neutral-300 mb-1">边框颜色</label>
            <div class="flex items-center gap-2">
              <input type="color" id="attrBorderColorPicker" value="#531DAB" class="w-8 h-8 rounded border border-neutral-100 cursor-pointer">
              <input type="text" id="attrBorderColorInput" value="#531DAB" class="flex-1 px-2 py-1 text-xs border border-neutral-100 rounded focus:border-primary outline-none">
            </div>
          </div>
        </div>
      </div>
      
      <!-- 连接线样式 -->
      <div class="space-y-3">
        <h4 class="text-sm font-medium text-neutral-300 flex items-center">
          <i class="fa fa-minus text-primary mr-2"></i>连接线样式
        </h4>
        <div class="space-y-2">
          <div>
            <label class="block text-xs text-neutral-300 mb-1">线条颜色</label>
            <div class="flex items-center gap-2">
              <input type="color" id="linkColorPicker" value="#86909C" class="w-8 h-8 rounded border border-neutral-100 cursor-pointer">
              <input type="text" id="linkColorInput" value="#86909C" class="flex-1 px-2 py-1 text-xs border border-neutral-100 rounded focus:border-primary outline-none">
            </div>
          </div>
          <div>
            <label class="block text-xs text-neutral-300 mb-1">线条粗细</label>
            <select id="linkWidthSelect" class="w-full px-3 py-2 text-sm border border-neutral-100 rounded-lg focus:border-primary focus:ring-1 focus:ring-primary/20 outline-none">
              <option value="1">1px</option>
              <option value="2" selected>2px</option>
              <option value="3">3px</option>
              <option value="4">4px</option>
              <option value="5">5px</option>
            </select>
          </div>
          <div>
            <label class="block text-xs text-neutral-300 mb-1">箭头显示</label>
            <div class="flex items-center gap-3">
              <label class="flex items-center cursor-pointer">
                <input type="radio" name="arrowOption" value="none" id="arrowNone" class="mr-2" checked>
                <span class="text-sm">无箭头</span>
              </label>
              <label class="flex items-center cursor-pointer">
                <input type="radio" name="arrowOption" value="arrow" id="arrowTo" class="mr-2">
                <span class="text-sm">指向功能</span>
              </label>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <div class="flex justify-between items-center mt-6 pt-4 border-t border-neutral-100">
      <div class="flex gap-3">
        <button id="resetStyleBtn" class="btn-secondary">
          <i class="fa fa-refresh"></i>
          <span>重置默认</span>
        </button>
        <button id="previewStyleBtn" class="btn-secondary">
          <i class="fa fa-eye"></i>
          <span>预览效果</span>
        </button>
      </div>
      <div class="flex gap-3">
        <button id="saveStyleBtn" class="btn-primary">
          <i class="fa fa-save"></i>
          <span>保存设置</span>
        </button>
        <button id="applyStyleBtn" class="btn-primary">
          <i class="fa fa-check"></i>
          <span>应用并关闭</span>
        </button>
      </div>
    </div>
  </div>
  
  <!-- 主内容区域 -->
  <main class="grid grid-cols-1 lg:grid-cols-4 h-[calc(100vh-8rem)] gap-4 p-4" id="mainContent">
    <!-- 左侧输入面板 -->
    <div class="lg:col-span-1">
      <div class="panel h-full flex flex-col overflow-hidden">
        <div class="p-4 border-b border-neutral-100">
          <h2 class="text-lg font-semibold flex items-center text-neutral-400">
            <i class="fa fa-pencil-square-o text-primary mr-2"></i>文本输入
          </h2>
        </div>
        
        <div class="p-4 border-b border-neutral-100">
          <label class="block text-sm font-medium text-neutral-300 mb-2">输入格式说明</label>
          <div class="bg-blue-50/50 border-l-4 border-primary p-4 rounded mb-4">
            <p class="text-sm text-neutral-300 space-y-1">
              <span class="font-semibold">1. 顶格输入</span>：角色名称（如"学生"）<br>
              <span class="font-semibold">2. 空格缩进</span>：该角色的功能（如" 学号"、" 姓名"）<br>
              <span class="font-semibold">3. 换行分隔</span>：不同角色或功能
            </p>
          </div>
        </div>
        
        <div class="flex-1 p-4">
          <textarea id="entityInput" class="input-field h-full resize-none bg-neutral-50/50" placeholder="例如：
学生
 学号
 姓名
 年级
 专业
 性别"></textarea>
        </div>
        
        <div class="p-4 border-t border-neutral-100">
          <div class="flex flex-col sm:flex-row gap-3">
            <button id="generateBtn" class="btn-primary flex-1">
              <i class="fa fa-magic"></i>
              <span>生成图表</span>
            </button>
            <button id="clearBtn" class="btn-secondary flex-1">
              <i class="fa fa-eraser"></i>
              <span>清空</span>
            </button>
          </div>
          
          <div class="mt-4 p-3 bg-neutral-50/50 rounded-lg flex items-center">
            <i class="fa fa-lightbulb-o text-warning mr-2"></i> 
            <p class="text-sm text-neutral-300">按 Ctrl+Enter 可快速生成图表</p>
          </div>
        </div>
      </div>
    </div>
    
    <!-- 右侧图表展示面板 -->
    <div class="lg:col-span-3">
      <div class="panel h-full flex flex-col overflow-hidden">
        <div class="p-4 border-b border-neutral-100 flex justify-between items-center">
          <h2 class="text-lg font-semibold flex items-center text-neutral-400">
            <i class="fa fa-object-group text-primary mr-2"></i>用例图
          </h2>
          <div class="flex gap-2">
            <button id="zoomInBtn" class="btn-secondary">
              <i class="fa fa-search-plus"></i>
            </button>
            <button id="zoomOutBtn" class="btn-secondary">
              <i class="fa fa-search-minus"></i>
            </button>
            <button id="resetViewBtn" class="btn-secondary">
              <i class="fa fa-expand"></i>
            </button>
            <button id="exportBtn" class="btn-secondary">
              <i class="fa fa-download"></i>
            </button>
            <button id="fullscreenBtn" class="btn-secondary">
              <i class="fa fa-arrows-alt"></i>
            </button>
          </div>
        </div>
        
        <div id="graphContainer" class="flex-1 w-full bg-white overflow-hidden relative">
          <!-- 图表将在这里显示 -->
          <div class="absolute inset-0 flex items-center justify-center">
            <div class="text-center">
              <div class="w-24 h-24 mx-auto mb-6 relative">
                <div class="w-full h-full rounded-full border-4 border-neutral-100 animate-pulse-slow"></div>
                <div class="absolute inset-0 flex items-center justify-center">
                  <i class="fa fa-sitemap text-4xl text-neutral-200"></i>
                </div>
              </div>
              <p class="text-lg text-neutral-300">输入文本并点击"生成图表"按钮</p>
              <p class="text-sm text-neutral-200 mt-1">或查看左侧的输入格式说明</p>
            </div>
          </div>
        </div>
        
        <div class="p-4 border-t border-neutral-100">
          <div class="grid grid-cols-2 gap-4">
            <div class="bg-blue-50/50 p-3 rounded-lg flex items-center">
              <div class="w-4 h-4 rounded-full bg-primary mr-2"></div>
              <span class="text-sm text-neutral-300">角色</span>
            </div>
            <div class="bg-purple-50/50 p-3 rounded-lg flex items-center">
              <div class="w-4 h-4 rounded-full bg-secondary mr-2"></div>
              <span class="text-sm text-neutral-300">功能</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </main>
  
  <!-- 模态框：图表导出选项 -->
  <div id="exportModal" class="fixed inset-0 bg-neutral-500/50 flex items-center justify-center z-50 hidden backdrop-blur-sm">
    <div class="bg-white rounded-xl shadow-lg w-full max-w-md transform transition-all duration-300 scale-95 opacity-0" id="modalContent">
      <div class="p-6 border-b border-neutral-100 flex justify-between items-center">
        <h3 class="text-lg font-semibold text-neutral-400">导出图表</h3>
        <button id="closeModalBtn" class="text-neutral-200 hover:text-neutral-400 transition-colors duration-200">
          <i class="fa fa-times"></i>
        </button>
      </div>
      
      <div class="p-6">
        <label class="block text-sm font-medium text-neutral-300 mb-2">选择格式</label>
        <div class="grid grid-cols-3 gap-3">
          <button class="border border-neutral-100 rounded-lg p-4 text-center hover:border-primary hover:text-primary transition-all duration-200">
            <i class="fa fa-file-image-o text-xl mb-2"></i>
            <p class="text-sm">PNG</p>
          </button>
          <button class="border border-neutral-100 rounded-lg p-4 text-center hover:border-primary hover:text-primary transition-all duration-200">
            <i class="fa fa-file-code-o text-xl mb-2"></i>
            <p class="text-sm">JSON</p>
          </button>
          <button class="border border-neutral-100 rounded-lg p-4 text-center hover:border-primary hover:text-primary transition-all duration-200">
            <i class="fa fa-file-text-o text-xl mb-2"></i>
            <p class="text-sm">文本</p>
          </button>
        </div>
        
        <div class="mt-6">
          <label class="block text-sm font-medium text-neutral-300 mb-2">文件名称</label>
          <input type="text" class="input-field" value="entity-graph" placeholder="输入文件名">
        </div>
        
        <div class="mt-6 flex justify-end">
          <button id="confirmExportBtn" class="btn-primary">
            <i class="fa fa-download"></i>
            <span>导出</span>
          </button>
        </div>
      </div>
    </div>
  </div>

  <script>
    // 配置管理
    const AppConfig = {
      // 默认配置
      defaults: {
        autoSave: true,
        autoGenerate: false,
        theme: 'light',
        layout: 'ForceDirected',
        entityColor: '#165DFF',
        attributeColor: '#722ED1',
        maxNodes: 100,
        autoZoomFit: true
      },
      
      // 获取配置
      get(key) {
        try {
          const stored = localStorage.getItem('entityGraph_config');
          const config = stored ? JSON.parse(stored) : {};
          return config[key] !== undefined ? config[key] : this.defaults[key];
        } catch (error) {
          console.warn('配置读取失败:', error);
          return this.defaults[key];
        }
      },
      
      // 设置配置
      set(key, value) {
        try {
          const stored = localStorage.getItem('entityGraph_config');
          const config = stored ? JSON.parse(stored) : {};
          config[key] = value;
          localStorage.setItem('entityGraph_config', JSON.stringify(config));
          return true;
        } catch (error) {
          console.warn('配置保存失败:', error);
          return false;
        }
      },
      
      // 重置配置
      reset() {
        try {
          localStorage.removeItem('entityGraph_config');
          return true;
        } catch (error) {
          console.warn('配置重置失败:', error);
          return false;
        }
      }
    };

    // 数据管理
    const DataManager = {
      // 自动保存输入内容
      autoSave(content) {
        if (AppConfig.get('autoSave')) {
          try {
            localStorage.setItem('entityGraph_lastInput', content);
            localStorage.setItem('entityGraph_lastSaved', new Date().toISOString());
          } catch (error) {
            console.warn('自动保存失败:', error);
          }
        }
      },
      
      // 恢复上次输入
      restore() {
        try {
          const content = localStorage.getItem('entityGraph_lastInput');
          const savedTime = localStorage.getItem('entityGraph_lastSaved');
          
          if (content && savedTime) {
            const timeDiff = Date.now() - new Date(savedTime).getTime();
            // 如果保存时间在24小时内，则恢复
            if (timeDiff < 24 * 60 * 60 * 1000) {
              return { content, savedTime };
            }
          }
          return null;
        } catch (error) {
          console.warn('数据恢复失败:', error);
          return null;
        }
      },
      
      // 清除保存的数据
      clear() {
        try {
          localStorage.removeItem('entityGraph_lastInput');
          localStorage.removeItem('entityGraph_lastSaved');
          return true;
        } catch (error) {
          console.warn('数据清除失败:', error);
          return false;
        }
      }
    };

    // GoJS 图表实例
    let myDiagram;
    
    // 默认样式配置 - 黑白配色方案
    const defaultStyles = {
      fontSize: '14',
      fontColor: '#000000',        // 字体颜色：黑色
      entityBgColor: '#FFFFFF',    // 实体背景：白色
      entityBorderColor: '#000000', // 实体边框：黑色
      attrBgColor: '#FFFFFF',      // 属性背景：白色
      attrBorderColor: '#000000',  // 属性边框：黑色
      linkColor: '#000000',        // 连接线颜色：黑色
      linkWidth: '2',
      showArrow: false             // 是否显示箭头：默认不显示
    };
    
    // 当前样式配置
    let currentStyles = { ...defaultStyles };
    
    // 初始化 GoJS 图表
    function initDiagram() {
      // 防止重复初始化
      if (myDiagram) {
        console.log('图表已存在，跳过重复初始化');
        return true;
      }
      
      // 检查 GoJS 是否已加载
      if (typeof go === 'undefined') {
        console.error('GoJS 库未加载');
        showNotification('GoJS 库加载失败，请刷新页面重试', 'error');
        return false;
      }
      
      // 清理可能存在的旧图表容器
      const container = document.getElementById('graphContainer');
      if (container) {
        // 保存空状态提示
        const emptyState = container.querySelector('.absolute');
        const emptyStateHTML = emptyState ? emptyState.outerHTML : '';
        
        // 清空容器
        container.innerHTML = emptyStateHTML;
      }
      
      const $ = go.GraphObject.make;
      
      // 设置 GoJS 许可证（尝试移除水印）
      if (typeof go !== 'undefined' && go.licenseKey !== undefined) {
        go.licenseKey = "";
      }
      
      myDiagram = $(go.Diagram, "graphContainer", {
        "undoManager.isEnabled": true,
        layout: $(go.Layout, {
          isOngoing: false,
          isInitial: true,
          isRealtime: false
        }),
        "toolManager.hoverDelay": 100,
        initialContentAlignment: go.Spot.Center,
        "animationManager.isEnabled": false,
        allowZoom: true,
        allowHorizontalScroll: true,
        allowVerticalScroll: true
      });

      // 设置画布背景为纯白色
      myDiagram.div.style.backgroundColor = "white";

      // 定义角色节点模板（小人形状）- 黑白配色
      myDiagram.nodeTemplateMap.add("Entity",
        $(go.Node, "Auto",
          {
            locationSpot: go.Spot.Center,
            selectionAdorned: true,
            resizable: false,
            layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized,
            // 设置角色的连接点为右侧，解决乱线问题
            fromSpot: go.Spot.Right,
            toSpot: go.Spot.Left
          },
          new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
          $(go.Panel, "Vertical",
            {
              // 为整个面板设置连接点
              portId: "",
              fromSpot: go.Spot.Right,
              toSpot: go.Spot.Left
            },
            // 小人的头部（圆形）
            $(go.Shape, "Circle",
              {
                name: "HEAD",
                width: 24,
                height: 24,
                fill: "#FFFFFF",
                stroke: "#000000",
                strokeWidth: 2,
                margin: new go.Margin(0, 0, 5, 0)
              },
              new go.Binding("fill", "isHighlighted", function(h) {
                return h ? "#F0F0F0" : "#FFFFFF";
              }).ofObject()
            ),
            // 小人的身体（线条组合）
            $(go.Panel, "Position",
              {
                width: 50,
                height: 60,
                background: "transparent"
              },
              // 身体
              $(go.Shape,
                {
                  name: "BODY",
                  geometryString: "M25,0 L25,35",
                  stroke: "#000000",
                  strokeWidth: 3
                }
              ),
              // 左臂
              $(go.Shape,
                {
                  name: "LEFT_ARM",
                  geometryString: "M25,12 L12,25",
                  stroke: "#000000",
                  strokeWidth: 2
                }
              ),
              // 右臂
              $(go.Shape,
                {
                  name: "RIGHT_ARM",
                  geometryString: "M25,12 L38,25",
                  stroke: "#000000",
                  strokeWidth: 2
                }
              ),
              // 左腿
              $(go.Shape,
                {
                  name: "LEFT_LEG",
                  geometryString: "M25,35 L12,55",
                  stroke: "#000000",
                  strokeWidth: 2
                }
              ),
              // 右腿
              $(go.Shape,
                {
                  name: "RIGHT_LEG",
                  geometryString: "M25,35 L38,55",
                  stroke: "#000000",
                  strokeWidth: 2
                }
              )
            ),
            // 角色名称
            $(go.TextBlock,
              {
                name: "TEXT",
                textAlign: "center",
                font: "bold 14px Inter, sans-serif",
                stroke: "#000000",
                margin: new go.Margin(8, 0, 0, 0),
                maxSize: new go.Size(100, NaN),
                wrap: go.TextBlock.WrapFit,
                editable: false
              },
              new go.Binding("text", "text")
            )
          )
        )
      );

      // 定义功能节点模板（椭圆）- 黑白配色，左对齐
      myDiagram.nodeTemplateMap.add("Attribute",
        $(go.Node, "Auto",
          {
            locationSpot: go.Spot.Left,  // 改为左对齐
            selectionAdorned: true,
            resizable: false,
            layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized,
            // 设置连接点为左侧
            fromSpot: go.Spot.Left,
            toSpot: go.Spot.Left
          },
          new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
          $(go.Shape, "Ellipse",
            {
              name: "SHAPE",
              fill: "#FFFFFF",      // 白色背景
              stroke: "#000000",    // 黑色边框
              strokeWidth: 2,
              minSize: new go.Size(80, 40),
              // 设置椭圆的连接点为左侧边缘
              portId: "",
              fromSpot: go.Spot.Left,
              toSpot: go.Spot.Left
            },
            new go.Binding("fill", "isHighlighted", function(h) {
              return h ? "#F0F0F0" : "#FFFFFF";  // 高亮时稍微变灰
            }).ofObject()
          ),
          $(go.TextBlock,
            {
              name: "TEXT",
              margin: 10,
              stroke: "#000000",    // 黑色字体
              font: "14px Inter, sans-serif",
              textAlign: "center",
              maxSize: new go.Size(120, NaN),
              wrap: go.TextBlock.WrapFit
            },
            new go.Binding("text", "text")
          )
        )
      );

      // 定义连接线模板 - 支持箭头，连接到椭圆左侧
      myDiagram.linkTemplate =
        $(go.Link,
          {
            routing: go.Link.Normal,
            curve: go.Link.None,
            corner: 0,
            toShortLength: 0,
            fromShortLength: 0,
            relinkableFrom: true,
            relinkableTo: true,
            reshapable: true,
            resegmentable: true,
            // 设置连接点：从角色右侧连接到功能左侧
            fromSpot: go.Spot.Right,
            toSpot: go.Spot.Left
          },
          new go.Binding("points").makeTwoWay(),
          $(go.Shape,
            {
              name: "LINK",
              isPanelMain: true,
              strokeWidth: 2,
              stroke: "#000000"     // 黑色连接线
            },
            new go.Binding("stroke", "isSelected", function(sel) {
              return sel ? "#666666" : "#000000";  // 选中时变为深灰色
            }).ofObject()
          ),
          $(go.Shape,
            {
              name: "ARROW",
              toArrow: "",  // 默认无箭头
              fill: "#000000",
              stroke: "#000000",
              strokeWidth: 1
            },
            new go.Binding("toArrow", "showArrow", function(show) {
              return show ? "Standard" : "";
            }),
            new go.Binding("fill", "isSelected", function(sel) {
              return sel ? "#666666" : "#000000";
            }).ofObject(),
            new go.Binding("stroke", "isSelected", function(sel) {
              return sel ? "#666666" : "#000000";
            }).ofObject()
          )
        );

      // 设置默认的节点和连接数据
      myDiagram.model = new go.GraphLinksModel([], []);
      
      // 移除水印
      removeGoJSWatermark();
      
      console.log('GoJS 图表初始化成功');
      return true;
    }
    
    // 移除 GoJS 水印
    function removeGoJSWatermark() {
      setTimeout(() => {
        const graphContainer = document.getElementById('graphContainer');
        if (graphContainer) {
          // 查找并隐藏水印元素
          const allDivs = graphContainer.querySelectorAll('div');
          allDivs.forEach(div => {
            const text = div.textContent || div.innerText;
            if (text && (text.includes('GoJS') || text.includes('gojs'))) {
              div.style.display = 'none';
              div.style.visibility = 'hidden';
              div.style.opacity = '0';
            }
          });
          
          // 使用 MutationObserver 监听新添加的水印
          if (!graphContainer.hasAttribute('data-watermark-observer')) {
            graphContainer.setAttribute('data-watermark-observer', 'true');
            
            const observer = new MutationObserver((mutations) => {
              mutations.forEach((mutation) => {
                mutation.addedNodes.forEach((node) => {
                  if (node.nodeType === 1 && node.tagName === 'DIV') {
                    const text = node.textContent || node.innerText;
                    if (text && (text.includes('GoJS') || text.includes('gojs'))) {
                      node.style.display = 'none';
                      node.style.visibility = 'hidden';
                      node.style.opacity = '0';
                    }
                  }
                });
              });
            });
            
            observer.observe(graphContainer, {
              childList: true,
              subtree: true
            });
          }
        }
      }, 100);
    }

    // 解析输入文本并生成图表数据
    function parseInput(text) {
      const startTime = performance.now();
      
      const lines = text.split('\n').filter(line => line.trim() !== '');
      const nodes = [];
      const links = [];
      let currentEntity = null;
      let nodeId = 0;
      let lineNumber = 0;

      // 输入格式验证
      const validationErrors = [];

      lines.forEach(line => {
        lineNumber++;
        const trimmedLine = line.trim();
        if (trimmedLine === '') return;

        // 检查是否为角色（顶格输入）
        if (!line.startsWith(' ') && !line.startsWith('\t')) {
          // 验证角色名称
          if (trimmedLine.length > 50) {
            validationErrors.push(`第 ${lineNumber} 行：角色名称过长（超过50字符）`);
          }
          if (!/^[\u4e00-\u9fa5a-zA-Z0-9_\-\s]+$/.test(trimmedLine)) {
            validationErrors.push(`第 ${lineNumber} 行：角色名称包含无效字符`);
          }
          
          // 这是一个角色
          currentEntity = {
            key: nodeId++,
            text: trimmedLine,
            category: "Entity",
            lineNumber: lineNumber
          };
          nodes.push(currentEntity);
        } else if (currentEntity) {
          // 验证功能名称
          if (trimmedLine.length > 30) {
            validationErrors.push(`第 ${lineNumber} 行：功能名称过长（超过30字符）`);
          }
          if (!/^[\u4e00-\u9fa5a-zA-Z0-9_\-\s]+$/.test(trimmedLine)) {
            validationErrors.push(`第 ${lineNumber} 行：功能名称包含无效字符`);
          }
          
          // 这是一个功能（有缩进）
          const attribute = {
            key: nodeId++,
            text: trimmedLine,
            category: "Attribute",
            lineNumber: lineNumber,
            parentEntity: currentEntity.text
          };
          nodes.push(attribute);
          
          // 创建从角色到功能的连接
          links.push({
            from: currentEntity.key,
            to: attribute.key,
            showArrow: currentStyles.showArrow
          });
        } else {
          validationErrors.push(`第 ${lineNumber} 行：功能必须在角色之后定义`);
        }
      });

      // 性能统计
      const endTime = performance.now();
      const parseTime = endTime - startTime;
      
      console.log(`解析性能统计:
        - 解析时间: ${parseTime.toFixed(2)}ms
        - 处理行数: ${lineNumber}
        - 生成节点: ${nodes.length}
        - 生成连接: ${links.length}
        - 验证错误: ${validationErrors.length}`);

      // 如果有验证错误，显示警告但不阻止生成
      if (validationErrors.length > 0) {
        console.warn('输入验证警告:', validationErrors);
        showNotification(`发现 ${validationErrors.length} 个格式警告，请检查控制台`, 'warning');
      }

      // 数据量检查
      if (nodes.length > 100) {
        showNotification('节点数量较多，可能影响性能', 'warning');
      }

      return { nodes, links, parseTime, validationErrors };
    }

    // 应用样式到图表
    function applyStylesToDiagram(styles) {
      if (!myDiagram) return;
      
      try {
        // 更新角色节点模板
        const entityTemplate = myDiagram.nodeTemplateMap.get("Entity");
        if (entityTemplate) {
          const entityHead = entityTemplate.findObject("HEAD");
          const entityBody = entityTemplate.findObject("BODY");
          const entityLeftArm = entityTemplate.findObject("LEFT_ARM");
          const entityRightArm = entityTemplate.findObject("RIGHT_ARM");
          const entityLeftLeg = entityTemplate.findObject("LEFT_LEG");
          const entityRightLeg = entityTemplate.findObject("RIGHT_LEG");
          const entityText = entityTemplate.findObject("TEXT");
          
          // 更新头部样式
          if (entityHead) {
            entityHead.fill = styles.entityBgColor;
            entityHead.stroke = styles.entityBorderColor;
          }
          
          // 更新身体和四肢的颜色
          const bodyColor = styles.entityBorderColor;
          if (entityBody) entityBody.stroke = bodyColor;
          if (entityLeftArm) entityLeftArm.stroke = bodyColor;
          if (entityRightArm) entityRightArm.stroke = bodyColor;
          if (entityLeftLeg) entityLeftLeg.stroke = bodyColor;
          if (entityRightLeg) entityRightLeg.stroke = bodyColor;
          
          // 更新文字样式
          if (entityText) {
            entityText.stroke = styles.fontColor;
            entityText.font = `bold ${styles.fontSize}px Inter, sans-serif`;
          }
        }
        
        // 更新属性节点模板
        const attrTemplate = myDiagram.nodeTemplateMap.get("Attribute");
        if (attrTemplate) {
          const attrShape = attrTemplate.findObject("SHAPE");
          const attrText = attrTemplate.findObject("TEXT");
          
          if (attrShape) {
            attrShape.fill = styles.attrBgColor;
            attrShape.stroke = styles.attrBorderColor;
          }
          if (attrText) {
            attrText.stroke = styles.fontColor;
            attrText.font = `${styles.fontSize}px Inter, sans-serif`;
          }
        }
        
        // 更新连接线模板
        if (myDiagram.linkTemplate) {
          const linkShape = myDiagram.linkTemplate.findObject("LINK");
          const arrowShape = myDiagram.linkTemplate.findObject("ARROW");
          if (linkShape) {
            linkShape.stroke = styles.linkColor;
            linkShape.strokeWidth = parseInt(styles.linkWidth);
          }
          if (arrowShape) {
            arrowShape.fill = styles.linkColor;
            arrowShape.stroke = styles.linkColor;
          }
        }
        
        // 更新现有节点的样式
        myDiagram.nodes.each(function(node) {
          if (node.category === "Entity") {
            // 角色节点（小人形状）的样式更新
            const head = node.findObject("HEAD");
            const body = node.findObject("BODY");
            const leftArm = node.findObject("LEFT_ARM");
            const rightArm = node.findObject("RIGHT_ARM");
            const leftLeg = node.findObject("LEFT_LEG");
            const rightLeg = node.findObject("RIGHT_LEG");
            const text = node.findObject("TEXT");
            
            // 更新头部样式
            if (head) {
              head.fill = styles.entityBgColor;
              head.stroke = styles.entityBorderColor;
            }
            
            // 更新身体和四肢的颜色
            const bodyColor = styles.entityBorderColor;
            if (body) body.stroke = bodyColor;
            if (leftArm) leftArm.stroke = bodyColor;
            if (rightArm) rightArm.stroke = bodyColor;
            if (leftLeg) leftLeg.stroke = bodyColor;
            if (rightLeg) rightLeg.stroke = bodyColor;
            
            // 更新文字样式
            if (text) {
              text.stroke = styles.fontColor;
              text.font = `bold ${styles.fontSize}px Inter, sans-serif`;
            }
          } else if (node.category === "Attribute") {
            const shape = node.findObject("SHAPE");
            const text = node.findObject("TEXT");
            if (shape) {
              shape.fill = styles.attrBgColor;
              shape.stroke = styles.attrBorderColor;
            }
            if (text) {
              text.stroke = styles.fontColor;
              text.font = `${styles.fontSize}px Inter, sans-serif`;
            }
          }
        });
        
        // 更新现有连接线的样式
        myDiagram.links.each(function(link) {
          const shape = link.findObject("LINK");
          const arrow = link.findObject("ARROW");
          if (shape) {
            shape.stroke = styles.linkColor;
            shape.strokeWidth = parseInt(styles.linkWidth);
          }
          if (arrow) {
            arrow.fill = styles.linkColor;
            arrow.stroke = styles.linkColor;
            // 强制更新箭头显示
            arrow.toArrow = styles.showArrow ? "Standard" : "";
          }
          // 更新箭头显示状态
          if (link.data) {
            link.data.showArrow = styles.showArrow;
          }
        });
        
        // 刷新图表
        myDiagram.requestUpdate();
        
        console.log('样式已应用:', styles);
        
      } catch (error) {
        console.error('应用样式时出错:', error);
        showNotification('应用样式时出现错误', 'error');
      }
    }

    // 生成图表
    function generateDiagram() {
      const inputText = document.getElementById('entityInput').value;
      
      // 输入验证
      if (!inputText.trim()) {
        showNotification('请输入角色和功能信息！', 'warning');
        return;
      }

      // 检查 GoJS 是否加载
      if (window.gojsLoadError) {
        showNotification('GoJS 库加载失败，无法生成图表。请刷新页面重试。', 'error');
        console.error('GoJS library failed to load from all CDN sources');
        return;
      }
      
      if (typeof go === 'undefined' && !window.gojsLoaded) {
        showNotification('GoJS 库正在加载中，请稍候再试...', 'warning');
        console.warn('GoJS library is still loading');
        return;
      }

      // 检查图表是否初始化
      if (!myDiagram) {
        showNotification('图表未初始化，正在重新初始化...', 'warning');
        try {
          initDiagram();
        } catch (initError) {
          console.error('图表初始化失败:', initError);
          showNotification('图表初始化失败，请刷新页面！', 'error');
          return;
        }
      }

      try {
        // 显示加载状态
        const generateBtn = document.getElementById('generateBtn');
        const originalText = generateBtn.innerHTML;
        generateBtn.innerHTML = '<i class="fa fa-spinner fa-spin"></i><span>生成中...</span>';
        generateBtn.disabled = true;

        const { nodes, links } = parseInput(inputText);
        
        if (nodes.length === 0) {
          showNotification('请检查输入格式！确保角色顶格输入，功能有缩进。', 'error');
          return;
        }

        // 数据验证
        const entityCount = nodes.filter(n => n.category === 'Entity').length;
        const attributeCount = nodes.filter(n => n.category === 'Attribute').length;
        
        console.log(`解析结果: ${entityCount} 个角色, ${attributeCount} 个功能, ${links.length} 个连接`);

        // 隐藏空状态提示
        const emptyState = document.querySelector('#graphContainer .absolute');
        if (emptyState) {
          emptyState.style.display = 'none';
        }

        // 更新图表模型
        myDiagram.model = new go.GraphLinksModel(nodes, links);
        
        // 强制更新所有连接线的箭头显示
        setTimeout(() => {
          myDiagram.links.each(function(link) {
            if (link.data) {
              link.data.showArrow = currentStyles.showArrow;
            }
            const arrow = link.findObject("ARROW");
            if (arrow) {
              arrow.toArrow = currentStyles.showArrow ? "Standard" : "";
            }
          });
          myDiagram.requestUpdate();
        }, 10);
        
        // 自定义布局：角色在左侧居中，功能在右侧垂直排列，形成扇子状
        setTimeout(() => {
          const entities = [];
          const attributes = [];
          
          // 分类节点
          myDiagram.nodes.each(function(node) {
            if (node.category === "Entity") {
              entities.push(node);
            } else if (node.category === "Attribute") {
              attributes.push(node);
            }
          });
          
          // 设置功能位置（右侧，垂直排列，左对齐）
          const attributeX = 400; // 功能椭圆的左边缘X坐标
          const attributeSpacing = 80;
          
          // 计算功能列表的总高度和起始Y位置，使其居中
          const totalAttributeHeight = (attributes.length - 1) * attributeSpacing;
          const attributeStartY = 200 - (totalAttributeHeight / 2);
          
          attributes.forEach((attr, index) => {
            const y = attributeStartY + (index * attributeSpacing);
            // 使用左对齐，所有椭圆的左边缘都在同一条垂直线上
            attr.location = new go.Point(attributeX, y);
          });
          
          // 设置角色位置（左侧，在功能列表的纵向中心）
          const entityX = 100;
          const entitySpacing = 200;
          
          entities.forEach((entity, index) => {
            // 角色位置在功能列表的中心高度
            const entityY = 200; // 与功能列表中心对齐
            const adjustedY = entityY + (index * entitySpacing); // 如果有多个角色，垂直分布
            entity.location = new go.Point(entityX, adjustedY);
          });
          
          // 刷新图表
          myDiagram.requestUpdate();
        }, 50);
        
        // 自动布局（禁用，使用自定义布局）
        // myDiagram.layoutDiagram(true);
        
        // 适应视图
        setTimeout(() => {
          try {
            myDiagram.zoomToFit();
            removeGoJSWatermark();
            
            // 应用当前样式配置到新生成的图表
            applyStylesToDiagram(currentStyles);
            
            showNotification(`用例图生成成功！包含 ${entityCount} 个角色和 ${attributeCount} 个功能`, 'success');
          } catch (viewError) {
            console.error('视图调整失败:', viewError);
            showNotification('图表生成成功，但视图调整失败', 'warning');
          } finally {
            // 恢复按钮状态
            generateBtn.innerHTML = originalText;
            generateBtn.disabled = false;
          }
        }, 100);
        
      } catch (error) {
        console.error('生成图表时出错:', error);
        showNotification(`生成图表时出错: ${error.message}`, 'error');
        
        // 恢复按钮状态
        const generateBtn = document.getElementById('generateBtn');
        generateBtn.innerHTML = '<i class="fa fa-magic"></i><span>生成图表</span>';
        generateBtn.disabled = false;
      }
    }

    // 显示通知
    function showNotification(message, type = 'info') {
      // 创建通知元素
      const notification = document.createElement('div');
      notification.className = `fixed top-20 right-6 z-50 flex items-center gap-3 px-4 py-3 rounded-lg shadow-lg text-white transform translate-x-full transition-transform duration-300`;
      
      // 根据类型设置背景色
      switch (type) {
        case 'success':
          notification.style.background = '#00B42A';
          break;
        case 'error':
          notification.style.background = '#F53F3F';
          break;
        case 'warning':
          notification.style.background = '#FF7D00';
          break;
        default:
          notification.style.background = '#168CFF';
      }
      
      notification.innerHTML = `
        <i class="fa fa-${type === 'success' ? 'check' : type === 'error' ? 'times' : type === 'warning' ? 'exclamation' : 'info'}-circle"></i>
        <span>${message}</span>
      `;
      
      // 添加到页面
      document.body.appendChild(notification);
      
      // 显示动画
      setTimeout(() => {
        notification.style.transform = 'translateX(0)';
      }, 100);
      
      // 自动隐藏
      setTimeout(() => {
        notification.style.transform = 'translateX(100%)';
        setTimeout(() => {
          document.body.removeChild(notification);
        }, 300);
      }, 3000);
    }

    // 导出图表为 PNG
    function exportToPNG(filename = 'use-case-diagram') {
      if (!myDiagram || myDiagram.nodes.count === 0) {
        showNotification('请先生成图表！', 'warning');
        return;
      }
      
      try {
        const imgData = myDiagram.makeImageData({
          background: "white",
          returnType: "string",
          callback: function(blob) {
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename + '.png';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            window.URL.revokeObjectURL(url);
            showNotification('图表已导出为 PNG！', 'success');
          }
        });
      } catch (error) {
        console.error('导出失败:', error);
        showNotification('导出失败，请重试！', 'error');
      }
    }

    // 导出为 JSON
    function exportToJSON(filename = 'use-case-diagram') {
      if (!myDiagram || myDiagram.nodes.count === 0) {
        showNotification('请先生成图表！', 'warning');
        return;
      }
      
      try {
        const modelData = myDiagram.model.toJson();
        const blob = new Blob([modelData], { type: 'application/json' });
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename + '.json';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(url);
        showNotification('图表已导出为 JSON！', 'success');
      } catch (error) {
        console.error('导出失败:', error);
        showNotification('导出失败，请重试！', 'error');
      }
    }

    // 导出为文本
    function exportToText(filename = 'entity-graph') {
      const inputText = document.getElementById('entityInput').value;
      if (!inputText.trim()) {
        showNotification('请先输入文本内容！', 'warning');
        return;
      }
      
      try {
        const blob = new Blob([inputText], { type: 'text/plain' });
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename + '.txt';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(url);
        showNotification('文本已导出！', 'success');
      } catch (error) {
        console.error('导出失败:', error);
        showNotification('导出失败，请重试！', 'error');
      }
    }

    // 页面加载完成后初始化
    document.addEventListener('DOMContentLoaded', function() {
      // 等待 GoJS 库加载完成
      let loadAttempts = 0;
      const maxAttempts = 100; // 最多等待 10 秒
      
      function waitForGoJS() {
        loadAttempts++;
        
        // 检查是否有加载错误
        if (window.gojsLoadError) {
          console.error('GoJS 库加载失败 - 所有 CDN 源都无法访问');
          showNotification('GoJS 库加载失败，请检查网络连接。建议使用离线版本或稍后重试。', 'error');
          return;
        }
        
        // 检查是否已成功加载
        if (typeof go !== 'undefined' || window.gojsLoaded) {
          console.log('GoJS 库加载成功，开始初始化图表');
          try {
            const success = initDiagram();
            if (success) {
              showNotification('图表初始化成功！', 'success');
            }
          } catch (error) {
            console.error('图表初始化失败:', error);
            showNotification('图表初始化失败，请刷新页面重试', 'error');
          }
        } else if (loadAttempts < maxAttempts) {
          // GoJS 未加载，等待 100ms 后重试
          setTimeout(waitForGoJS, 100);
          
          // 每 2 秒显示一次加载进度
          if (loadAttempts % 20 === 0) {
            console.log(`等待 GoJS 库加载... (${loadAttempts/10}s)`);
          }
        } else {
          // 超时，显示错误信息
          console.error('GoJS 库加载超时');
          showNotification('GoJS 库加载超时，请刷新页面重试或检查网络连接', 'error');
        }
      }
      
      // 开始等待 GoJS 加载
      waitForGoJS();
      
      // 获取元素
      const generateBtn = document.getElementById('generateBtn');
      const clearBtn = document.getElementById('clearBtn');
      const zoomInBtn = document.getElementById('zoomInBtn');
      const zoomOutBtn = document.getElementById('zoomOutBtn');
      const resetViewBtn = document.getElementById('resetViewBtn');
      const exportBtn = document.getElementById('exportBtn');
      const exportModal = document.getElementById('exportModal');
      const modalContent = document.getElementById('modalContent');
      const closeModalBtn = document.getElementById('closeModalBtn');
      const confirmExportBtn = document.getElementById('confirmExportBtn');
      const entityInput = document.getElementById('entityInput');
      const fullscreenBtn = document.getElementById('fullscreenBtn');
      const helpBtn = document.getElementById('helpBtn');
      const settingsBtn = document.getElementById('settingsBtn');
      const themeToggle = document.getElementById('themeToggle');
      
      // 设置默认示例文本或恢复上次输入
      const restored = DataManager.restore();
      if (restored && restored.content) {
        entityInput.value = restored.content;
        const savedDate = new Date(restored.savedTime).toLocaleString();
        showNotification(`已恢复上次保存的内容 (${savedDate})`, 'info');
      } else {
        entityInput.value = `学生
 学号
 姓名
 年级
 专业
 性别

教师
 工号
 姓名
 职称
 部门
 联系方式

课程
 课程号
 课程名
 学分
 学时
 先修课程`;
      }
      
      // 输入框变化时自动保存
      let saveTimeout;
      entityInput.addEventListener('input', function() {
        // 防抖保存
        clearTimeout(saveTimeout);
        saveTimeout = setTimeout(() => {
          DataManager.autoSave(this.value);
        }, 1000);
      });
      
      // 按钮点击事件 - 生成图表
      generateBtn.addEventListener('click', generateDiagram);
      
      // 按钮点击事件 - 清空输入
      clearBtn.addEventListener('click', function() {
        entityInput.value = '';
        // 显示空状态
        const emptyState = document.querySelector('#graphContainer .absolute');
        if (emptyState) {
          emptyState.style.display = 'flex';
        }
        // 清空图表
        if (myDiagram) {
          myDiagram.model = new go.GraphLinksModel([], []);
        }
      });
      
      // 按钮点击事件 - 缩放控制
      zoomInBtn.addEventListener('click', function() {
        if (myDiagram) {
          myDiagram.commandHandler.increaseZoom();
        }
      });
      
      zoomOutBtn.addEventListener('click', function() {
        if (myDiagram) {
          myDiagram.commandHandler.decreaseZoom();
        }
      });
      
      resetViewBtn.addEventListener('click', function() {
        if (myDiagram) {
          myDiagram.zoomToFit();
        }
      });
      
      // 按钮点击事件 - 导出图表
      exportBtn.addEventListener('click', function() {
        exportModal.classList.remove('hidden');
        // 添加动画
        setTimeout(() => {
          modalContent.classList.remove('scale-95', 'opacity-0');
          modalContent.classList.add('scale-100', 'opacity-100');
        }, 10);
      });
      
      // 关闭模态框
      closeModalBtn.addEventListener('click', function() {
        // 添加关闭动画
        modalContent.classList.remove('scale-100', 'opacity-100');
        modalContent.classList.add('scale-95', 'opacity-0');
        setTimeout(() => {
          exportModal.classList.add('hidden');
        }, 300);
      });
      
      // 导出格式选择
      const exportButtons = exportModal.querySelectorAll('.grid button');
      let selectedFormat = 'PNG';
      
      exportButtons.forEach((btn, index) => {
        btn.addEventListener('click', function() {
          // 移除其他按钮的选中状态
          exportButtons.forEach(b => b.classList.remove('border-primary', 'text-primary'));
          // 添加当前按钮的选中状态
          this.classList.add('border-primary', 'text-primary');
          
          // 设置选中的格式
          const formats = ['PNG', 'JSON', '文本'];
          selectedFormat = formats[index];
        });
      });
      
      // 确认导出
      confirmExportBtn.addEventListener('click', function() {
        const filenameInput = exportModal.querySelector('input[type="text"]');
        const filename = filenameInput.value || 'entity-graph';
        
        // 根据选择的格式导出
        switch (selectedFormat) {
          case 'PNG':
            exportToPNG(filename);
            break;
          case 'JSON':
            exportToJSON(filename);
            break;
          case '文本':
            exportToText(filename);
            break;
        }
        
        // 关闭模态框
        modalContent.classList.remove('scale-100', 'opacity-100');
        modalContent.classList.add('scale-95', 'opacity-0');
        setTimeout(() => {
          exportModal.classList.add('hidden');
        }, 300);
      });
      
      // 点击模态框外部关闭
      exportModal.addEventListener('click', function(e) {
        if (e.target === exportModal) {
          // 添加关闭动画
          modalContent.classList.remove('scale-100', 'opacity-100');
          modalContent.classList.add('scale-95', 'opacity-0');
          setTimeout(() => {
            exportModal.classList.add('hidden');
          }, 300);
        }
      });
      
      // 快捷键支持
      entityInput.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.key === 'Enter') {
          generateBtn.click();
          e.preventDefault();
        }
      });
      
      // 全屏按钮
      fullscreenBtn.addEventListener('click', function() {
        const graphContainer = document.getElementById('graphContainer');
        
        if (!document.fullscreenElement) {
          if (graphContainer.requestFullscreen) {
            graphContainer.requestFullscreen();
          } else if (graphContainer.webkitRequestFullscreen) { /* Safari */
            graphContainer.webkitRequestFullscreen();
          } else if (graphContainer.msRequestFullscreen) { /* IE11 */
            graphContainer.msRequestFullscreen();
          }
        } else {
          if (document.exitFullscreen) {
            document.exitFullscreen();
          } else if (document.webkitExitFullscreen) { /* Safari */
            document.webkitExitFullscreen();
          } else if (document.msExitFullscreen) { /* IE11 */
            document.msExitFullscreen();
          }
        }
      });
      
      // 帮助按钮
      helpBtn.addEventListener('click', function() {
        showNotification('实体顶格输入，属性空格缩进，按 Ctrl+Enter 快速生成', 'info');
      });
      
      // 设置按钮 - 打开个性化设置面板
      settingsBtn.addEventListener('click', function() {
        const customizePanel = document.getElementById('customizePanel');
        const mainContent = document.getElementById('mainContent');
        
        if (customizePanel.classList.contains('hidden')) {
          customizePanel.classList.remove('hidden');
          mainContent.classList.remove('h-[calc(100vh-8rem)]');
          mainContent.classList.add('h-[calc(100vh-16rem)]');
          showNotification('个性化设置面板已打开', 'info');
        } else {
          customizePanel.classList.add('hidden');
          mainContent.classList.remove('h-[calc(100vh-16rem)]');
          mainContent.classList.add('h-[calc(100vh-8rem)]');
        }
      });
      
      // 个性化设置面板功能
      const customizePanel = document.getElementById('customizePanel');
      const closeCustomizeBtn = document.getElementById('closeCustomizeBtn');
      const resetStyleBtn = document.getElementById('resetStyleBtn');
      const previewStyleBtn = document.getElementById('previewStyleBtn');
      const saveStyleBtn = document.getElementById('saveStyleBtn');
      const applyStyleBtn = document.getElementById('applyStyleBtn');
      
      // 获取所有颜色选择器和输入框
      const fontColorPicker = document.getElementById('fontColorPicker');
      const fontColorInput = document.getElementById('fontColorInput');
      const entityBgColorPicker = document.getElementById('entityBgColorPicker');
      const entityBgColorInput = document.getElementById('entityBgColorInput');
      const entityBorderColorPicker = document.getElementById('entityBorderColorPicker');
      const entityBorderColorInput = document.getElementById('entityBorderColorInput');
      const attrBgColorPicker = document.getElementById('attrBgColorPicker');
      const attrBgColorInput = document.getElementById('attrBgColorInput');
      const attrBorderColorPicker = document.getElementById('attrBorderColorPicker');
      const attrBorderColorInput = document.getElementById('attrBorderColorInput');
      const linkColorPicker = document.getElementById('linkColorPicker');
      const linkColorInput = document.getElementById('linkColorInput');
      const fontSizeSelect = document.getElementById('fontSizeSelect');
      const linkWidthSelect = document.getElementById('linkWidthSelect');
      
      // 同步颜色选择器和输入框
      function syncColorInputs(picker, input) {
        picker.addEventListener('input', function() {
          input.value = this.value;
          updateCurrentStyles();
        });
        
        input.addEventListener('input', function() {
          if (/^#[0-9A-F]{6}$/i.test(this.value)) {
            picker.value = this.value;
            updateCurrentStyles();
          }
        });
      }
      
      // 设置所有颜色输入框的同步
      syncColorInputs(fontColorPicker, fontColorInput);
      syncColorInputs(entityBgColorPicker, entityBgColorInput);
      syncColorInputs(entityBorderColorPicker, entityBorderColorInput);
      syncColorInputs(attrBgColorPicker, attrBgColorInput);
      syncColorInputs(attrBorderColorPicker, attrBorderColorInput);
      syncColorInputs(linkColorPicker, linkColorInput);
      
      // 监听选择框变化
      fontSizeSelect.addEventListener('change', updateCurrentStyles);
      linkWidthSelect.addEventListener('change', updateCurrentStyles);
      
      // 监听箭头选项变化
      const arrowOptions = document.querySelectorAll('input[name="arrowOption"]');
      arrowOptions.forEach(option => {
        option.addEventListener('change', updateCurrentStyles);
      });
      
      // 更新当前样式配置
      function updateCurrentStyles() {
        const selectedArrowOption = document.querySelector('input[name="arrowOption"]:checked');
        currentStyles = {
          fontSize: fontSizeSelect.value,
          fontColor: fontColorInput.value,
          entityBgColor: entityBgColorInput.value,
          entityBorderColor: entityBorderColorInput.value,
          attrBgColor: attrBgColorInput.value,
          attrBorderColor: attrBorderColorInput.value,
          linkColor: linkColorInput.value,
          linkWidth: linkWidthSelect.value,
          showArrow: selectedArrowOption ? selectedArrowOption.value === 'arrow' : false
        };
      }
      

      
      // 关闭个性化设置面板
      closeCustomizeBtn.addEventListener('click', function() {
        customizePanel.classList.add('hidden');
        const mainContent = document.getElementById('mainContent');
        mainContent.classList.remove('h-[calc(100vh-16rem)]');
        mainContent.classList.add('h-[calc(100vh-8rem)]');
      });
      
      // 重置为默认样式
      resetStyleBtn.addEventListener('click', function() {
        // 清除本地存储的样式设置
        localStorage.removeItem('diagramStyles');
        
        // 重置所有输入框到默认值
        fontSizeSelect.value = defaultStyles.fontSize;
        fontColorPicker.value = defaultStyles.fontColor;
        fontColorInput.value = defaultStyles.fontColor;
        entityBgColorPicker.value = defaultStyles.entityBgColor;
        entityBgColorInput.value = defaultStyles.entityBgColor;
        entityBorderColorPicker.value = defaultStyles.entityBorderColor;
        entityBorderColorInput.value = defaultStyles.entityBorderColor;
        attrBgColorPicker.value = defaultStyles.attrBgColor;
        attrBgColorInput.value = defaultStyles.attrBgColor;
        attrBorderColorPicker.value = defaultStyles.attrBorderColor;
        attrBorderColorInput.value = defaultStyles.attrBorderColor;
        linkColorPicker.value = defaultStyles.linkColor;
        linkColorInput.value = defaultStyles.linkColor;
        linkWidthSelect.value = defaultStyles.linkWidth;
        
        // 重置箭头选项
        const arrowOption = defaultStyles.showArrow ? 'arrow' : 'none';
        const arrowElement = document.querySelector(`input[name="arrowOption"][value="${arrowOption}"]`);
        if (arrowElement) {
          arrowElement.checked = true;
        }
        
        // 重置当前样式配置
        currentStyles = { ...defaultStyles };
        
        // 立即应用默认样式到图表
        applyStylesToDiagram(currentStyles);
        
        showNotification('已完全重置为默认样式并清除保存的设置', 'success');
      });
      
      // 预览效果
      previewStyleBtn.addEventListener('click', function() {
        updateCurrentStyles();
        applyStylesToDiagram(currentStyles);
        
        // 强制更新所有连接线的箭头显示
        setTimeout(() => {
          myDiagram.links.each(function(link) {
            if (link.data) {
              link.data.showArrow = currentStyles.showArrow;
            }
            const arrow = link.findObject("ARROW");
            if (arrow) {
              arrow.toArrow = currentStyles.showArrow ? "Standard" : "";
            }
          });
          myDiagram.requestUpdate();
        }, 10);
        
        showNotification('预览效果已应用', 'info');
      });
      
      // 保存设置
      saveStyleBtn.addEventListener('click', function() {
        updateCurrentStyles();
        localStorage.setItem('diagramStyles', JSON.stringify(currentStyles));
        showNotification('样式设置已保存', 'success');
      });
      
      // 应用并关闭
      applyStyleBtn.addEventListener('click', function() {
        updateCurrentStyles();
        applyStylesToDiagram(currentStyles);
        
        // 强制更新所有连接线的箭头显示
        setTimeout(() => {
          myDiagram.links.each(function(link) {
            if (link.data) {
              link.data.showArrow = currentStyles.showArrow;
            }
            const arrow = link.findObject("ARROW");
            if (arrow) {
              arrow.toArrow = currentStyles.showArrow ? "Standard" : "";
            }
          });
          myDiagram.requestUpdate();
        }, 10);
        
        localStorage.setItem('diagramStyles', JSON.stringify(currentStyles));
        
        customizePanel.classList.add('hidden');
        const mainContent = document.getElementById('mainContent');
        mainContent.classList.remove('h-[calc(100vh-16rem)]');
        mainContent.classList.add('h-[calc(100vh-8rem)]');
        
        showNotification('样式已应用并保存', 'success');
      });
      
      // 页面加载时初始化样式
      function initializeStyles() {
        // 始终使用默认样式初始化界面
        fontSizeSelect.value = defaultStyles.fontSize;
        fontColorPicker.value = defaultStyles.fontColor;
        fontColorInput.value = defaultStyles.fontColor;
        entityBgColorPicker.value = defaultStyles.entityBgColor;
        entityBgColorInput.value = defaultStyles.entityBgColor;
        entityBorderColorPicker.value = defaultStyles.entityBorderColor;
        entityBorderColorInput.value = defaultStyles.entityBorderColor;
        attrBgColorPicker.value = defaultStyles.attrBgColor;
        attrBgColorInput.value = defaultStyles.attrBgColor;
        attrBorderColorPicker.value = defaultStyles.attrBorderColor;
        attrBorderColorInput.value = defaultStyles.attrBorderColor;
        linkColorPicker.value = defaultStyles.linkColor;
        linkColorInput.value = defaultStyles.linkColor;
        linkWidthSelect.value = defaultStyles.linkWidth;
        
        // 初始化箭头选项（添加错误检查）
        const arrowOption = defaultStyles.showArrow ? 'arrow' : 'none';
        const arrowElement = document.querySelector(`input[name="arrowOption"][value="${arrowOption}"]`);
        if (arrowElement) {
          arrowElement.checked = true;
        } else {
          console.warn('箭头选项元素未找到:', arrowOption);
        }
        
        // 设置当前样式为默认样式
        currentStyles = { ...defaultStyles };
        
        // 延迟应用默认样式，确保图表已初始化
        setTimeout(() => {
          applyStylesToDiagram(currentStyles);
        }, 1000);
      }
      
      // 在页面加载完成后初始化样式
      setTimeout(initializeStyles, 1500);
      
      // 主题系统
      const ThemeManager = {
        // 获取当前主题
        getCurrentTheme() {
          return localStorage.getItem('theme') || 'light';
        },
        
        // 设置主题
        setTheme(theme) {
          document.documentElement.setAttribute('data-theme', theme);
          localStorage.setItem('theme', theme);
          this.updateThemeIcon(theme);
          this.updateThemeRadios(theme);
        },
        
        // 更新主题图标
        updateThemeIcon(theme) {
          const icon = themeToggle.querySelector('i');
          icon.className = theme === 'dark' ? 'fa fa-sun-o' : 'fa fa-moon-o';
        },
        
        // 更新主题单选按钮
        updateThemeRadios(theme) {
          const lightRadio = document.getElementById('lightTheme');
          const darkRadio = document.getElementById('darkTheme');
          if (lightRadio && darkRadio) {
            lightRadio.checked = theme === 'light';
            darkRadio.checked = theme === 'dark';
          }
        },
        
        // 切换主题
        toggleTheme() {
          const currentTheme = this.getCurrentTheme();
          const newTheme = currentTheme === 'light' ? 'dark' : 'light';
          this.setTheme(newTheme);
          showNotification(`已切换到${newTheme === 'dark' ? '深色' : '浅色'}模式`, 'info');
        },
        
        // 初始化主题
        init() {
          const savedTheme = this.getCurrentTheme();
          this.setTheme(savedTheme);
          
          // 监听系统主题变化
          const autoThemeCheckbox = document.getElementById('autoTheme');
          if (autoThemeCheckbox) {
            const isAuto = localStorage.getItem('autoTheme') === 'true';
            autoThemeCheckbox.checked = isAuto;
            
            if (isAuto) {
              this.enableAutoTheme();
            }
          }
        },
        
        // 启用自动主题
        enableAutoTheme() {
          const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
          const handleChange = (e) => {
            const theme = e.matches ? 'dark' : 'light';
            this.setTheme(theme);
          };
          
          // 立即应用系统主题
          handleChange(mediaQuery);
          
          // 监听系统主题变化
          mediaQuery.addListener(handleChange);
          
          // 保存监听器引用以便后续移除
          this.mediaQueryListener = handleChange;
          this.mediaQuery = mediaQuery;
        },
        
        // 禁用自动主题
        disableAutoTheme() {
          if (this.mediaQuery && this.mediaQueryListener) {
            this.mediaQuery.removeListener(this.mediaQueryListener);
          }
        }
      };
      
      // 主题切换按钮事件
      themeToggle.addEventListener('click', function() {
        // 如果启用了自动主题，先禁用它
        const autoThemeCheckbox = document.getElementById('autoTheme');
        if (autoThemeCheckbox && autoThemeCheckbox.checked) {
          autoThemeCheckbox.checked = false;
          localStorage.setItem('autoTheme', 'false');
          ThemeManager.disableAutoTheme();
        }
        
        ThemeManager.toggleTheme();
      });
      
      // 主题单选按钮事件
      const lightThemeRadio = document.getElementById('lightTheme');
      const darkThemeRadio = document.getElementById('darkTheme');
      const autoThemeCheckbox = document.getElementById('autoTheme');
      
      if (lightThemeRadio) {
        lightThemeRadio.addEventListener('change', function() {
          if (this.checked) {
            // 禁用自动主题
            if (autoThemeCheckbox) {
              autoThemeCheckbox.checked = false;
              localStorage.setItem('autoTheme', 'false');
              ThemeManager.disableAutoTheme();
            }
            ThemeManager.setTheme('light');
            showNotification('已切换到浅色模式', 'info');
          }
        });
      }
      
      if (darkThemeRadio) {
        darkThemeRadio.addEventListener('change', function() {
          if (this.checked) {
            // 禁用自动主题
            if (autoThemeCheckbox) {
              autoThemeCheckbox.checked = false;
              localStorage.setItem('autoTheme', 'false');
              ThemeManager.disableAutoTheme();
            }
            ThemeManager.setTheme('dark');
            showNotification('已切换到深色模式', 'info');
          }
        });
      }
      
      if (autoThemeCheckbox) {
        autoThemeCheckbox.addEventListener('change', function() {
          const isAuto = this.checked;
          localStorage.setItem('autoTheme', isAuto.toString());
          
          if (isAuto) {
            ThemeManager.enableAutoTheme();
            showNotification('已启用跟随系统主题', 'info');
          } else {
            ThemeManager.disableAutoTheme();
            showNotification('已禁用跟随系统主题', 'info');
          }
        });
      }
      
      // 初始化主题系统
      ThemeManager.init();
      
      // 为按钮添加悬停效果
      const buttons = document.querySelectorAll('button');
      buttons.forEach(button => {
        button.addEventListener('mouseenter', function() {
          this.classList.add('scale-105');
        });
        button.addEventListener('mouseleave', function() {
          this.classList.remove('scale-105');
        });
      });
      
      // 注释掉自动生成，避免重复初始化
      // setTimeout(() => {
      //   generateDiagram();
      // }, 500);
    });
  </script>
</body>
</html>
    